package com.glsc.ngateway.platform.service.itflow.flowstrategy.equipmentModify;

import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractCreateParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractFlowSearchParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractPassParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.formData.equipment.EquipmentModifyTaskFormDataDto;
import com.glsc.ngateway.common.api.flowable.dto.task.formData.equipment.domainDto.FlowFormEquipmentModifyDto;
import com.glsc.ngateway.common.api.oaflow.feign.IFeignOaFlowService;
import com.glsc.ngateway.common.api.platform.dto.user.PlatformUserDto;
import com.glsc.ngateway.common.base.converter.platform.FlowFormEquipmentModifyCloudDeviceDetailConverter;
import com.glsc.ngateway.common.base.converter.platform.FlowFormEquipmentModifyConverter;
import com.glsc.ngateway.common.base.converter.platform.FlowFormEquipmentModifyServerDetailConverter;
import com.glsc.ngateway.common.base.converter.platform.FlowFormEquipmentModifyVirtualDeviceDetailConverter;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.flow.FlowFormEquipmentModify;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.ItDict;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.ItDictData;
import com.glsc.ngateway.common.base.domain.mysql.gateway.system.SystemMain;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowEnum;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowTaskEnum;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowTaskParamEnum;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowTaskRoleEnum;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.*;
import com.glsc.ngateway.platform.service.FlowCommonService;
import com.glsc.ngateway.platform.service.RoleService;
import com.glsc.ngateway.platform.service.UserService;
import com.glsc.ngateway.platform.service.it.DictionaryService;
import com.glsc.ngateway.platform.service.itflow.flowstrategy.AbstractItFlowStrategy;
import com.glsc.ngateway.platform.service.itflow.flowstrategy.equipmentModify.taskPostHandler.IEquipmentModifyTaskPostHandlerAudit;
import com.glsc.ngateway.platform.service.system.SystemMainService;
import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.validation.constraints.NotBlank;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备变更流程策略类
 *
 * @author xuchang
 */
@Getter
@Component
public class EquipmentModifyFlowStrategy extends AbstractItFlowStrategy<FlowFormEquipmentModifyDto, EquipmentModifyTaskFormDataDto> {

    private final Logger logger = LoggerFactory.getLogger(EquipmentModifyFlowStrategy.class);

    @Resource
    private FlowFormEquipmentModifyRepo equipmentModifyRepo;

    @Resource
    private FlowFormEquipmentModifyServerRepo equipmentModifyServerRepo;

    @Resource
    private FlowFormEquipmentModifyCloudDeviceRepo equipmentModifyCloudServerRepo;

    @Resource
    private FlowFormEquipmentModifyVirtualDeviceRepo equipmentModifyVirtualDeviceRepo;

    @Resource
    private RoleService roleService;

    @Resource
    private UserService userService;

    @Autowired
    private IFeignOaFlowService oaFlowService;

    @Autowired
    private DictionaryService dictionaryService;

    private Map<String, IEquipmentModifyTaskPostHandlerAudit> taskPostHandlerMap;

    @Autowired
    public void setTaskPostHandlerMap(List<IEquipmentModifyTaskPostHandlerAudit> taskPostHandlerList) {
        this.taskPostHandlerMap = taskPostHandlerList.stream()
                .collect(Collectors.toMap(IEquipmentModifyTaskPostHandlerAudit::getTaskDefinitionKey, handler -> handler));
    }

    @Resource
    private FlowCommonService flowCommonService;

    @Resource
    private AppendixRepo appendixRepo;

    @Autowired
    private SystemMainService systemMainService;

    @Override
    public ITFlowEnum getFlowEnum() {
        return ITFlowEnum.EQUIPMENT_MODIFY;
    }

    @Override
    protected <A extends AbstractCreateParamDto<FlowFormEquipmentModifyDto, EquipmentModifyTaskFormDataDto>> void checkDataBeforeCreateFlow(A taskDto) throws PlatformException {
        if (Objects.isNull(taskDto) || Objects.isNull(taskDto.getFlowableFormData())) {
            throw PlatformException.error("数据为空", false, false);
        }
        EquipmentModifyTaskFormDataDto formData = taskDto.getFlowableFormData();
        checkData(formData);
    }

    private static void checkData(EquipmentModifyTaskFormDataDto formData) {
        boolean nonEquipmentModified = true;
        //检查服务器设备
        if (!CollectionUtils.isEmpty(formData.getFormServerDataList())) {
            nonEquipmentModified = false;
        }
        //检查虚拟机
        if (!CollectionUtils.isEmpty(formData.getFormVirtualDeviceDataList())) {
            nonEquipmentModified = false;
        }
        //检查云平台
        if (!CollectionUtils.isEmpty(formData.getFormCloudDeviceDataList())) {
            nonEquipmentModified = false;
        }
        if (nonEquipmentModified) {
            throw PlatformException.error("没有设备被变更", false, false);
        }
    }

    @Override
    protected <A extends AbstractPassParamDto<FlowFormEquipmentModifyDto, EquipmentModifyTaskFormDataDto>> void checkDataBeforePassTask(A passDto) throws PlatformException {
        if (Objects.isNull(passDto) || Objects.isNull(passDto.getFlowableFormData())) {
            throw PlatformException.error("数据为空", false, false);
        }
        //被退回到初始节点重新提交后，仍然要检查一次
        if (passDto.getTaskDefinitionKey().equals(ITFlowTaskEnum.MODIFY_FLOW_BEGIN_TASK.getTaskKey())) {
            checkData(passDto.getFlowableFormData());
        }
    }

    @Override
    protected Map<String, List<String>> initDefaultTaskUserGroup(PlatformUserDto creator) throws PlatformException {
        //流程节点，发起时动态指定节点处理人
        Map<String, List<String>> taskAssignee = new HashMap<>();
        //1、发起人
        taskAssignee.put(ITFlowTaskParamEnum.MODIFY_FLOW_BEGIN_TASK_ASSIGNMENTS.getName(), Arrays.asList(creator.getUsername()));
        //2、直属ld+一级部门负责人
        List<String> superList = userService.getDirectLeaderAndPrimaryDepartmentLeader(creator).getAllLeaders();
        if (!CollectionUtils.isEmpty(superList)) {
            taskAssignee.put(ITFlowTaskParamEnum.MODIFY_FLOW_DEPARTMENT_SUPER_TASK_ASSIGNMENTS.getName(), superList);
        }
        //3、设备管理员
        List<String> deviceAdminList = roleService.getUsersByRole(ITFlowTaskRoleEnum.ROLE_DEVICE_ADMIN.getRoleName());
        if (CollectionUtils.isEmpty(deviceAdminList)) {
            throw PlatformException.error("未找到设备管理员", false, false);
        }
        taskAssignee.put(ITFlowTaskParamEnum.MODIFY_FLOW_DEVICE_ADMIN_TASK_ASSIGNMENTS.getName(), deviceAdminList);
        //4、信息技术总部基础架构部负责人
        List<String> frameworkHeadList = roleService.getUsersByRole(ITFlowTaskRoleEnum.ROLE_FRAMEWORK_HEAD.getRoleName());
        if (CollectionUtils.isEmpty(frameworkHeadList)) {
            throw PlatformException.error("未找到信息技术总部基础架构部负责人", false, false);
        }
        taskAssignee.put(ITFlowTaskParamEnum.MODIFY_FLOW_FRAMEWORK_HEAD_TASK_ASSIGNMENTS.getName(), frameworkHeadList);
        //5、设备管理员和病毒管理岗
        List<String> virusManagerList = roleService.getUsersByRole(ITFlowTaskRoleEnum.ROLE_VIRUS_MANAGER.getRoleName());
        if (!CollectionUtils.isEmpty(deviceAdminList)) {
            taskAssignee.put(ITFlowTaskParamEnum.MODIFY_FLOW_HEAD_QUARTERS_ADMIN_TASK_ASSIGNMENTS.getName(), virusManagerList);
        }
        if (!CollectionUtils.isEmpty(virusManagerList)) {
            taskAssignee.put(ITFlowTaskParamEnum.MODIFY_VIRUS_MANAGE_TASK_ASSIGNMENTS.getName(), virusManagerList);
        }
        return taskAssignee;
    }

    @Override
    protected Map<String, String> initDefaultTaskConditionalVar(Map<String, String> taskAssignee, PlatformUserDto createUser) {
        return Collections.EMPTY_MAP;
//        return new HashMap<>() {{
//            put(EquipmentTaskParamNameEnum.DEPARTMENT_SUPER_TASK_CARDINALITY.getName(), taskAssignee.get(EquipmentTaskParamNameEnum.DEPARTMENT_SUPER_TASK_CARDINALITY.getName()));
//            put(EquipmentTaskParamNameEnum.DEVICE_ADMIN_TASK_CARDINALITY.getName(), taskAssignee.get(EquipmentTaskParamNameEnum.DEVICE_ADMIN_TASK_CARDINALITY.getName()));
//            put(EquipmentTaskParamNameEnum.HEAD_QUARTERS_ADMIN_TASK_CARDINALITY.getName(), taskAssignee.get(EquipmentTaskParamNameEnum.HEAD_QUARTERS_ADMIN_TASK_CARDINALITY.getName()));
//        }};
    }

    @Override
    public EquipmentModifyTaskFormDataDto saveOrUpdateForm(EquipmentModifyTaskFormDataDto flowableForm) {
        if (StringUtils.isNotBlank(flowableForm.getProcessId())) {
            flowableForm.getFormMainData().setProcessId(flowableForm.getProcessId());
        }
        FlowFormEquipmentModify oldData = equipmentModifyRepo.findByProcessId(flowableForm.getFormMainData().getProcessId());
        if (Objects.nonNull(oldData)) {
            flowableForm.getFormMainData().setId(oldData.getId());
        }
        FlowFormEquipmentModify equipmentModify = equipmentModifyRepo.save(Objects.requireNonNull(FlowFormEquipmentModifyConverter.dto2Do(flowableForm.getFormMainData())));
        Long equipmentModifyId = equipmentModify.getId();
        if (!CollectionUtils.isEmpty(flowableForm.getFormServerDataList())) {
            FlowFormEquipmentModifyServerDetailConverter.dto2Do(flowableForm.getFormServerDataList())
                    .forEach(server -> {
                        server.setEquipmentModifyId(equipmentModifyId);
                        equipmentModifyServerRepo.save(server);
                    });
        }
        if (!CollectionUtils.isEmpty(flowableForm.getFormCloudDeviceDataList())) {
            FlowFormEquipmentModifyCloudDeviceDetailConverter.dto2Do(flowableForm.getFormCloudDeviceDataList())
                    .forEach(cloud -> {
                        cloud.setEquipmentModifyId(equipmentModifyId);
                        equipmentModifyCloudServerRepo.save(cloud);
                    });
        }
        if (!CollectionUtils.isEmpty(flowableForm.getFormVirtualDeviceDataList())) {
            FlowFormEquipmentModifyVirtualDeviceDetailConverter.dto2Do(flowableForm.getFormVirtualDeviceDataList())
                    .forEach(virtual -> {
                        virtual.setEquipmentModifyId(equipmentModifyId);
                        equipmentModifyVirtualDeviceRepo.save(virtual);
                    });
        }
        return flowableForm;
    }

    @Override
    public EquipmentModifyTaskFormDataDto findFormByProcessId(String processId) {
        //主表信息
        EquipmentModifyTaskFormDataDto formDataDto = new EquipmentModifyTaskFormDataDto();
        FlowFormEquipmentModify equipmentFlow = equipmentModifyRepo.findByProcessId(processId);
        boolean nullFlag = Objects.isNull(equipmentFlow);
        formDataDto.setFormMainData(nullFlag ? new FlowFormEquipmentModifyDto() : FlowFormEquipmentModifyConverter.do2Dto(equipmentFlow));
        //服务器设备信息
        formDataDto.setFormServerDataList(nullFlag ? Collections.emptyList() : FlowFormEquipmentModifyServerDetailConverter.do2Dto(equipmentModifyServerRepo.findByEquipmentModifyId(equipmentFlow.getId())));
        //虚拟机信息
        formDataDto.setFormVirtualDeviceDataList(nullFlag ? Collections.emptyList() : FlowFormEquipmentModifyVirtualDeviceDetailConverter.do2Dto(equipmentModifyVirtualDeviceRepo.findByEquipmentModifyId(equipmentFlow.getId())));
        //云平台信息
        formDataDto.setFormCloudDeviceDataList(nullFlag ? Collections.emptyList() : FlowFormEquipmentModifyCloudDeviceDetailConverter.do2Dto(equipmentModifyCloudServerRepo.findByEquipmentModifyId(equipmentFlow.getId())));

        return formDataDto;
    }

    @Override
    public List<String> pageProcessId(AbstractFlowSearchParamDto param, Pageable pageable) {
        return equipmentModifyRepo.findAll(
                        (Specification<FlowFormEquipmentModify>) (root, query, builder) -> {
                            List<Predicate> predicateList = new ArrayList<>();
                            if (!io.jsonwebtoken.lang.Collections.isEmpty(param.getAdminList())) {
                                predicateList.add(builder.in(root.get("flowCreateOperatorName")).value(param.getAdminList()));
                            }
                            if (StringUtils.isNotBlank(param.getTitle())) {
                                predicateList.add(builder.equal(root.get("flowTitle"), param.getTitle()));
                            }
                            if (Objects.nonNull(param.getBeginDateLocalDate())) {
                                predicateList.add(builder.greaterThanOrEqualTo(root.get("flowApplyTime"), param.getBeginDateLocalDate()));
                            }
                            if (Objects.nonNull(param.getEndDateLocalDate())) {
                                predicateList.add(builder.lessThanOrEqualTo(root.get("flowApplyTime"), param.getEndDateLocalDate()));
                            }
                            if (Objects.nonNull(param.getHasProcessEnd())) {
                                predicateList.add(builder.equal(root.get("isClose"), param.getHasProcessEnd()));
                            }
                            return builder.and(predicateList.toArray(new Predicate[0]));
                        }, pageable)
                .getContent()
                .stream()
                .map(FlowFormEquipmentModify::getProcessId)
                .collect(Collectors.toList());
    }

    /**
     * 处理OA侧消息
     */
    @Override
    public void doHandle(@NotBlank String workflowId, @NotBlank String requestId, String description) {
        JSONObject jsonObj = JSON.parseObject(oaFlowService.getRequestData(requestId));
        if (!"SUCCESS".equals(jsonObj.get("status"))) {
            throw PlatformException.error("OA设备变更流程：处理失败，请求oa获取流程信息异常");
        }
        JSONArray dataArr = (JSONArray) jsonObj.get("data");
        if (Objects.isNull(dataArr)) {
            throw PlatformException.error(String.format("OA设备变更流程：处理失败，未找到流程信息, workflowId-{}, requestId-{}", workflowId, requestId));
        }
        JSONObject data = (JSONObject) dataArr.get(0);
        JSONObject flowInfos = (JSONObject) data.get("flowInfos");
        //操作类型：系统变更　系统上线　系统切换　系统下线
        String flowType = flowInfos.containsKey("flowType") ? (String) flowInfos.get("flowType"): Strings.EMPTY;
        //系统编号
        String systemNum = (String) flowInfos.get("systemNum");
        if (Strings.isBlank(flowType) || Strings.isBlank(systemNum)) {
            logger.error("OA设备变更流程：workflowId-{}, requestId-{}, 操作类型-{}, 系统编号-{}", workflowId, requestId, flowType, systemNum);
        } else {
            ItDict status = null;
            ItDictData itBuildStatus = dictionaryService.findByDictData("it_build_status");
            switch (flowType) {
                case "0":
                    //系统变更
                    break;
                case "1":
                    //系统上线
                    status = itBuildStatus.getDictValues().stream().filter(d -> "使用中".equals(d.getDictValue())).findAny().orElseThrow(
                            () -> PlatformException.error(String.format("OA设备变更流程：处理失败, 未找到字典it_build_status下的【使用中】信息, workflowId-{}, requestId-{},", systemNum, workflowId, requestId)));
                    break;
                case "2":
                    //系统切换
                    logger.info("OA设备变更流程：操作类型非下线,不做处理, workflowId-{}, requestId-{}, 操作类型-{}, 系统编号-{}", workflowId, requestId, flowType, systemNum);
                    break;
                case "3":
                    //系统下线
                    status = itBuildStatus.getDictValues().stream().filter(d -> "停止运行".equals(d.getDictValue())).findAny().orElseThrow(
                            () -> PlatformException.error(String.format("OA设备变更流程：处理失败, 未找到字典it_build_status下的【停止运行】信息, workflowId-{}, requestId-{},", systemNum, workflowId, requestId)));
                    break;
                default:
                    logger.error("OA设备变更流程：未匹配到操作类型，不做处理");
            }
            if(Objects.nonNull(status)) {
                //修改状态为【停止运行】
                SystemMain systemMain = systemMainService.findBySystemClassNo(systemNum);
                if (Objects.isNull(systemMain)) {
                    throw PlatformException.error(String.format("OA设备变更流程：处理失败, 未找到本地系统{}信息, workflowId-{}, requestId-{},", systemNum, workflowId, requestId));
                }
                systemMain.setStatus(status.getDictSubentry());
                systemMainService.addOrUpdate(systemMain,"系统流程");
            }
        }
    }

    @Override
    protected Map<String, IEquipmentModifyTaskPostHandlerAudit> getTaskPassMap() {
        return taskPostHandlerMap;
    }

    @Override
    protected Map<String, IEquipmentModifyTaskPostHandlerAudit> getTaskRejectMap() {
        return taskPostHandlerMap;
    }
}
